package pl.soulmusic.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.stream.XMLStreamException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;

import pl.soulmusic.data.dao.AlbumsMapper;
import pl.soulmusic.data.dao.ArtistsMapper;
import pl.soulmusic.data.dao.GenresMapper;
import pl.soulmusic.data.dao.ListenedTracksMapper;
import pl.soulmusic.data.dao.POITracksMapper;
import pl.soulmusic.data.dao.POIsMapper;
import pl.soulmusic.data.dao.TracksMapper;
import pl.soulmusic.data.dao.UsersMapper;
import pl.soulmusic.data.model.Albums;
import pl.soulmusic.data.model.AlbumsExample;
import pl.soulmusic.data.model.Artists;
import pl.soulmusic.data.model.ArtistsExample;
import pl.soulmusic.data.model.Genres;
import pl.soulmusic.data.model.GenresExample;
import pl.soulmusic.data.model.ListenedTracks;
import pl.soulmusic.data.model.ListenedTracksExample;
import pl.soulmusic.data.model.POITracksKey;
import pl.soulmusic.data.model.POIs;
import pl.soulmusic.data.model.POIsExample;
import pl.soulmusic.data.model.Tracks;
import pl.soulmusic.data.model.TracksExample;
import pl.soulmusic.data.model.Users;
import pl.soulmusic.data.model.UsersExample;

/**
 * A utility class for accessing the data base.
 */
public class StorageUtils {
    private static final Log log = LogFactory.getLog(StorageUtils.class);

    /**
     * Retrieves the coordination context with the specified transaction id.
     * 
     * @param transactionId
     *            the transaction id of the coordination context
     * @return the retrieved coordination context
     * @throws Exception
     */
    public static void addNewPOI(String name, String description,
	    double latitude, double longitude, double maxDistance, int user)
	    throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    POIsMapper tabela = sesion.getMapper(POIsMapper.class);

	    POIs p = new POIs();
	    p.setName(name);
	    p.setDescription(description);
	    p.setLatitude(latitude);
	    p.setLongitude(longitude);
	    p.setMax_distance(maxDistance);
	    p.setUser(user);
	    tabela.insert(p);
	    Character i;
	    return;
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}

    }

    /**
     * Method checks if exist user with such passhash in database
     * 
     * @param login
     *            - user login
     * @param passHash
     *            - hash created from receive password
     * @return -1 if user with such passHash does not exist, user ID if such
     *         user exists
     * @throws Exception
     */
    public static int existUser(String login, String passHash) throws Exception {

	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    UsersMapper tabela = sesion.getMapper(UsersMapper.class);
	    UsersExample ex = new UsersExample();
	    ex.createCriteria().andLoginEqualTo(login).andPass_hashEqualTo(
		    passHash);
	    List<Users> list = tabela.selectByExample(ex);
	    if (list.size() == 0)
		return -1;
	    return list.get(0).getId();
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }

    public static int getPOIid(String poiName, int userID) throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    POIsMapper tabela = sesion.getMapper(POIsMapper.class);
	    POIsExample ex = new POIsExample();
	    ex.createCriteria().andNameEqualTo(poiName).andUserEqualTo(userID);
	    List<POIs> list = tabela.selectByExample(ex);
	    if (list.size() == 0) {
		ex = new POIsExample();
		ex.createCriteria().andNameEqualTo(poiName).andUserEqualTo(1);
		list = tabela.selectByExample(ex);
		if (list.size() == 0)
		    return -1;
		return list.get(0).getId();
	    }
	    return list.get(0).getId();
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }

    public static int getOrAddGenre(String genreName) throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    GenresMapper tabela = sesion.getMapper(GenresMapper.class);
	    GenresExample ex = new GenresExample();
	    ex.createCriteria().andNameEqualTo(genreName);
	    List<Genres> list = tabela.selectByExample(ex);
	    if (list.size() == 0) {
		Genres genre = new Genres();
		genre.setName(genreName);
		tabela.insert(genre);
		list = tabela.selectByExample(ex);
		if (list.size() == 0) {
		    return -1;
		}
		return list.get(0).getId();
	    }
	    return list.get(0).getId();
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }

    public static int getOrAddArtist(String artistName, String artistCountry)
	    throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    ArtistsMapper tabela = sesion.getMapper(ArtistsMapper.class);
	    ArtistsExample ex = new ArtistsExample();
	    ex.createCriteria().andNameEqualTo(artistName);
	    List<Artists> list = tabela.selectByExample(ex);
	    if (list.size() == 0) {
		Artists artist = new Artists();
		artist.setName(artistName);
		artist.setCountry(artistCountry);
		tabela.insert(artist);
		list = tabela.selectByExample(ex);
		return list.get(0).getId();
	    }
	    return list.get(0).getId();
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }

    public static int getOrAddAlbum(String albumName, String albumYear,
	    int artistID) throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    AlbumsMapper tabela = sesion.getMapper(AlbumsMapper.class);
	    AlbumsExample ex = new AlbumsExample();
	    ex.createCriteria().andNameEqualTo(albumName);
	    List<Albums> list = tabela.selectByExample(ex);
	    if (list.size() == 0) {
		Albums album = new Albums();
		album.setName(albumName);
		album.setYear(albumYear);
		album.setArtist(artistID);
		tabela.insert(album);
		list = tabela.selectByExample(ex);
		return list.get(0).getId();
	    }
	    return list.get(0).getId();
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }

    public static int getOrAddTrack(String trackTitle, String trackYouUrl,
	    int artistID, int genreID, int albumID) throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    TracksMapper tabela = sesion.getMapper(TracksMapper.class);
	    TracksExample ex = new TracksExample();
	    ex.createCriteria().andTitleEqualTo(trackTitle);
	    List<Tracks> list = tabela.selectByExample(ex);
	    if (list.size() == 0) {
		Tracks track = new Tracks();
		track.setTitle(trackTitle);
		track.setYoutube_url(trackYouUrl);
		track.setArtist(artistID);
		track.setGenre(genreID);
		track.setAlbum(albumID);
		tabela.insert(track);
		list = tabela.selectByExample(ex);
		return list.get(0).getId();
	    }
	    return list.get(0).getId();
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }

    public static int addListenedTrack(Timestamp timestamp, double latitude ,double longitude,
	    int trackID, int userID) throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    ListenedTracksMapper tabela = sesion
		    .getMapper(ListenedTracksMapper.class);

	    ListenedTracks track = new ListenedTracks();
	    track.setLatitude(latitude);
	    track.setLongitude(longitude);
	    track.setTimestamp(timestamp);
	    track.setTrack(trackID);
	    track.setUser(userID);

	    if (tabela.insert(track) <= 0)
		throw new Exception("Nie dodano sciezki");

	    ListenedTracksExample ex=new ListenedTracksExample();
	    ex.createCriteria().andTimestampEqualTo(timestamp).andTrackEqualTo(trackID).andUserEqualTo(userID);
	    return tabela.selectByExample(ex).get(0).getId();
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }
    public static List<POIs> getPOIs(int userID) throws Exception {
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    POIsMapper tabela = sesion.getMapper(POIsMapper.class);
	    POIsExample ex = new POIsExample();
		ex.createCriteria().andUserEqualTo(userID);
		List<POIs> list = tabela.selectByExample(ex);
		ex = new POIsExample();
		ex.createCriteria().andUserEqualTo(0);
		List<POIs> list2 =tabela.selectByExample(ex);
		POIs[] sl = (POIs[]) list.toArray(new POIs[0]);
		for(POIs poi : sl){
		 list2.add(poi);   
		}
		return list2;
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    }
    public static void addPOITrack(int ListTrackID, int POIid) throws Exception{
	SqlSession sesion = SqlMapFactory.getInstance();
	try {
	    POITracksMapper tabela = sesion.getMapper(POITracksMapper.class);
	    POITracksKey record = new POITracksKey();
	    record.setListened_track(ListTrackID);
	    record.setPoi(POIid);
	    tabela.insert(record);
	} catch (Exception e) {
	    // log.error("On insert!:", e);
	    throw e;
	} finally {
	    if (sesion != null) {
		sesion.commit();
		sesion.close();
	    }
	}
    
    }
}
